﻿#ifndef JFUTUREWATCHER_H
#define JFUTUREWATCHER_H

#include "jconcurrent_global.h"
#include "jfuture.h"

// - interface JFutureWatcherBaseObserver -

class JFutureWatcherBaseObserver
{
public:
    virtual void started() { }
    virtual void finished() { }
    virtual void canceled() { }
    virtual void paused() { }
    virtual void resumed() { }
    virtual void resultReadyAt(int resultIndex) { J_UNUSED(resultIndex); }
    virtual void resultsReadyAt(int beginIndex, int endIndex) { J_UNUSED(beginIndex); J_UNUSED(endIndex); }
    virtual void progressRangeChanged(int minimum, int maximum) { J_UNUSED(minimum); J_UNUSED(maximum); }
    virtual void progressValueChanged(int progressValue) { J_UNUSED(progressValue); }
    virtual void progressTextChanged(const jstring &progressText) { J_UNUSED(progressText); }
};

// - class JFutureWatcherBase -

class JFutureWatcherBasePrivate;

class JCONCURRENT_EXPORT JFutureWatcherBase
{
public:
    JFutureWatcherBase();
    virtual ~JFutureWatcherBase();

    int progressValue() const;
    int progressMinimum() const;
    int progressMaximum() const;
    jstring progressText() const;

    bool isStarted() const;
    bool isFinished() const;
    bool isRunning() const;
    bool isCanceled() const;
    bool isPaused() const;

    void waitForFinished();

    void setPendingResultsLimit(int limit);

public:
    void cancel();
    void setPaused(bool paused);
    void pause();
    void resume();
    void togglePaused();

protected:
    // called from setFuture() implemented in template sub-classes
    void connectOutputInterface();
    void disconnectOutputInterface(bool pendingAssignment = false);

private:
    // implemented in the template sub-classes
    virtual const JFutureInterfaceBase &futureInterface() const = 0;
    virtual JFutureInterfaceBase &futureInterface() = 0;

private:
    J_DISABLE_COPY(JFutureWatcherBase)
    J_DECLARE_PRIVATE(JFutureWatcherBase)
    J_DECLARE_OBSERVER(JFutureWatcherBase)
};

template <typename T>
class JFutureWatcher : public JFutureWatcherBase
{
public:
    JFutureWatcher()
        : JFutureWatcherBase()
    { }
    ~JFutureWatcher()
    { disconnectOutputInterface(); }

    void setFuture(const JFuture<T> &future);
    JFuture<T> future() const
    { return m_future; }

    T result() const { return m_future.result(); }
    T resultAt(int index) const { return m_future.resultAt(index); }

private:
    JFuture<T> m_future;
    const JFutureInterfaceBase &futureInterface() const { return m_future.d; }
    JFutureInterfaceBase &futureInterface() { return m_future.d; }
};

template <typename T>
inline void JFutureWatcher<T>::setFuture(const JFuture<T> &_future)
{
    if (_future == m_future)
        return;

    disconnectOutputInterface(true);
    m_future = _future;
    connectOutputInterface();
}

template <>
class JFutureWatcher<void> : public JFutureWatcherBase
{
public:
    JFutureWatcher()
        : JFutureWatcherBase()
    { }
    ~JFutureWatcher()
    { disconnectOutputInterface(); }

    void setFuture(const JFuture<void> &future);
    JFuture<void> future() const
    { return m_future; }

private:
    JFuture<void> m_future;
    const JFutureInterfaceBase &futureInterface() const { return m_future.d; }
    JFutureInterfaceBase &futureInterface() { return m_future.d; }
};

inline void JFutureWatcher<void>::setFuture(const JFuture<void> &_future)
{
    if (_future == m_future) {
        return;
    }

    disconnectOutputInterface(true);
    m_future = _future;
    connectOutputInterface();
}

#endif // JFUTUREWATCHER_H
